package com.example.javamaday.graph;

import java.util.Stack;

/**
 * 深度优先搜索 路径查找（无向图）
 */
public class DepthFirstPath {

    private boolean[] marked;  //索引代表顶点，值表示当前顶点是否已经被搜索

    private int s; // 起点

    private int[] edgeTo; // 索引代表顶带你，值代表从起点s到当前顶带你路径上的最后一个顶点

    // 使用深度优先搜索对象，找出G图中起点为s的所有路径
    private DepthFirstPath(Graph g, int s) {
        this.marked = new boolean[g.V()];
        this.s = s;
        this.edgeTo = new int[g.V()];
        dfs(g, s);
    }

    private void dfs(Graph g, int v) {
        marked[v] = true;
        for (Integer w : g.adj(v)) {
            if (!marked[w]) {
                edgeTo[w] = v; // 到达顶点w的路径上的最后一个顶点是v
                dfs(g, w);
            }
        }
    }

    // 顶点s和顶点v之间是否存在路径
    public boolean hasPathTo(int v) {
        return marked[v];
    }

    // 输出起点s到顶点v之间的路径（就是该路径经过的顶点）
    public Stack<Integer> pathTo(int v) {
        if (!hasPathTo(v)) {
            return null;
        }
        Stack<Integer> pathStack = new Stack<>();
        // 通过循环，从顶点v开始，一直往前找，直到找到起点为止
        for (int x = v; x != s; x = edgeTo[x]) {
            pathStack.push(x);
        }
        // 最后把起点放入到栈中
        pathStack.push(s);
        return pathStack;
    }

    public static void main(String[] args) {
        // 准备一幅图
        Graph graph = new Graph(13);
        graph.addEdge(0, 5);
        graph.addEdge(0, 1);
        graph.addEdge(0, 2);
        graph.addEdge(0, 6);
        graph.addEdge(5, 3);
        graph.addEdge(5, 4);
        graph.addEdge(3, 4);
        graph.addEdge(4, 6);

        graph.addEdge(7, 8);

        graph.addEdge(9, 11);
        graph.addEdge(9, 10);
        graph.addEdge(9, 12);
        graph.addEdge(11, 12);
        // 准备深度优先搜索对象
        DepthFirstPath depthFirstPath = new DepthFirstPath(graph, 0);
        Stack<Integer> result = depthFirstPath.pathTo(3);

        while (!result.empty()) {
            System.out.println(result.pop());
        }
    }

}
